﻿#region Copyright © 2013 Paul Miller (Millz)
// All rights are reserved. Reproduction or transmission in whole or in part,
// any form or by any means, electronic, mechanical or otherwise, is prohibited
// without the prior written consent of the copyright owner.
// 
// Filename: CachedObjects.cs
// Date:     23/09/2013
// Author:   Paul Miller (Millz)
#endregion

//!CompilerOption:AddRef:System.Runtime.Caching.dll

using System;
using System.Linq;
using Insanity.Helpers;
using Styx;
using Styx.WoWInternals.WoWObjects;

namespace Insanity.Managers
{
    internal static class CachedObjects
    {
        #region CacheManager structs
        /// <summary>
        /// To work with the cache manager
        /// </summary>
        private class BoolCache
        {
            public bool State;
        }

        private class uIntCache
        {
            public uint Value;
        }

        #endregion

        #region Expiry Timers

        private const int CachedCanUseEquippedItemExpiry = 1000;
        private const int HasEngineeringOver450Expiry = 30000;
        private const int CachedLatencyExpiry = 1000;
        private const int CachedHaveItemExpiry = 5000;

        #endregion

        #region InBgOrArena
        /// <summary>
        /// CurrentMap.IsArena || ..IsBattleground
        /// </summary>
        /// <param name="u"></param>
        /// <returns></returns>
        public static bool InBgOrArena(this WoWUnit u)
        {
            try
            {
                if (u == null || !u.IsValid) return false;

                return (StyxWoW.Me.CurrentMap.IsArena || StyxWoW.Me.CurrentMap.IsBattleground);
                   
            }
            catch (Exception e)
            {
                Log.Debug("Exception thrown at CachedObject.InBgOrArena: {0}", e);
                return StyxWoW.Me.CurrentMap.IsArena || StyxWoW.Me.CurrentMap.IsBattleground;
            }
        }

        #endregion

        #region CachedCanUseEquippedItem

        public static bool CachedCanUseEquippedItem(this WoWItem item)
        {
            try
            {
                if (item == null) return false;

                string cacheKey = "canuseitem" + item.Guid;
                var getStatus = CacheManager.Get<BoolCache>(cacheKey);
                if (getStatus == null)
                {
                    var itemSpell = Styx.WoWInternals.Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);

                    if (string.IsNullOrEmpty(itemSpell))
                    {
                        getStatus = new BoolCache { State = false };
                        CacheManager.Add(getStatus, cacheKey, CachedCanUseEquippedItemExpiry);
                    }
                    else
                    {
                        getStatus = new BoolCache { State = item.Usable && item.Cooldown <= 0 };
                    }

                }
                return getStatus.State;
            }
            catch (Exception e)
            {
                Log.Debug("Exception thrown at CachedObject.CachedCanUseEquippedItem: {0}", e);
                var itemSpell = Styx.WoWInternals.Lua.GetReturnVal<string>("return GetItemSpell(" + item.Entry + ")", 0);
                if (string.IsNullOrEmpty(itemSpell))
                    return false;

                return item.Usable && item.Cooldown <= 0;
            }
        }
        #endregion

        #region HasEngineeringOver450

        public static bool HasEngineeringOver450()
        {
            try
            {
                const string cacheKey = "engineering";
                var getStatus = CacheManager.Get<BoolCache>(cacheKey);
                if (getStatus == null)
                {
                    getStatus = new BoolCache { State = StyxWoW.Me.GetSkill(SkillLine.Engineering).CurrentValue >= 450 };
                    CacheManager.Add(getStatus, cacheKey, HasEngineeringOver450Expiry);
                }
                return getStatus.State;
            }
            catch (Exception e)
            {
                Log.Debug("Exception thrown at CachedObject.HasEngineeringOver450(): {0}", e);
                return StyxWoW.Me.GetSkill(SkillLine.Engineering).CurrentValue >= 450;
            }
        }
        #endregion

        #region CachedLatency
        /// <summary>
        /// Cached version of WoWClient.Latency
        /// </summary>
        /// <returns></returns>
        public static uint CachedLatency()
        {
            try
            {
                const string cacheKey = "CachedLatency";
                var getStatus = CacheManager.Get<uIntCache>(cacheKey);
                if (getStatus == null)
                {
                    getStatus = new uIntCache { Value = StyxWoW.WoWClient.Latency };
                    CacheManager.Add(getStatus, cacheKey, CachedLatencyExpiry);
                }
                return getStatus.Value;
            }
            catch (Exception e)
            {
                Log.Debug("Exception thrown at CachedObject.CachedLatency: {0}", e);
                return StyxWoW.WoWClient.Latency;
            }
        }

        #endregion

        #region CachedHaveItem
        public static bool CachedHaveItem(this int item)
        {
            try
            {
                string cacheKey = "CachedHaveItem" + item;
                var getStatus = CacheManager.Get<BoolCache>(cacheKey);

                if (getStatus == null)
                {
                    getStatus = new BoolCache { State = StyxWoW.Me.BagItems.FirstOrDefault(x => x.Entry == item && x.Usable) != null };
                    CacheManager.Add(getStatus, cacheKey, CachedHaveItemExpiry);
                }
                return getStatus.State;
            }
            catch (Exception e)
            {
                Log.Debug("Exception thrown at CachedObject.CachedHaveItem: {0}", e);
                return StyxWoW.Me.BagItems.FirstOrDefault(x => x.Entry == item && x.Usable) != null;
            }
        }
        #endregion
    }
}
